﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Netfraction.Hub.Scripting;

namespace NetfractionHub.Security
{
    public class PermissionBuilder : TypeBuilder
    {
        public static bool TryParse(string fullname, out AccessPermissionBase accessPermission)
        {
            accessPermission = Create(GetClassType(Assembly.GetCallingAssembly(), fullname));
            return accessPermission != null;
        }

        public static AccessPermissionBase Create(string fullname)
        {
            return Create(GetClassType(Assembly.GetCallingAssembly(), fullname));
        }

        public static AccessPermissionBase Create(string fullname, AccessState state)
        {

            return Create(GetClassType(Assembly.GetCallingAssembly(), fullname), state);
        }

        public static AccessPermissionBase Create(Type type)
        {
            return (AccessPermissionBase)Activator.CreateInstance(type);
        }

        public static AccessPermissionBase Create(Type type, AccessState state)
        {
            return (AccessPermissionBase)Activator.CreateInstance(type, new object[] { state });
        }

        public static AccessPermissionBase Create(PermissionSourceData data)
        {
            return Create(data, AccessState.Default);
        }

        public static AccessPermissionBase Create(PermissionSourceData data, AccessState initialState)
        {
            if (data == null)
                throw new ArgumentNullException("data");

            switch (data.Source.CodeType)
            {
                case SourceCodeType.BuiltIn:
                    return CreateInternalType(data, initialState);
                case SourceCodeType.CompiledAssembly:
                    return CreateExternalType(data, initialState);
                case SourceCodeType.DLRScript:
                    // this will compile code from a source code file
                    return null;
                default:
                    return null;
            }
        }

        private static AccessPermissionBase CreateInternalType(PermissionSourceData data)
        {
            return CreateInternalType(data, AccessState.Default);
        }

        private static AccessPermissionBase CreateInternalType(PermissionSourceData data, AccessState initialState)
        {
            object[] ctorArgs = initialState == AccessState.Default ? null : new object[] { initialState };
            AccessPermissionBase apb = null;
            try
            {
                apb = (AccessPermissionBase)Activator.CreateInstance(GetClassType(Assembly.GetCallingAssembly(), data.FullName), ctorArgs);
            }
            catch (TypeLoadException tle)
            {
                Console.WriteLine(tle.Message);
                return null;
            }
            catch (ArgumentNullException ane)
            {
                Console.WriteLine(ane.Message);
                return null;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return null;
            }
            return apb;
        }

        private static AccessPermissionBase CreateExternalType(PermissionSourceData data)
        {
            return CreateExternalType(data, AccessState.Default);
        }

        private static AccessPermissionBase CreateExternalType(PermissionSourceData data, AccessState initialState)
        {
            AccessPermissionBase apb = null;
            Assembly externalDll = null;
            string dllPath = Core.GetScriptsDirectory();

            if (Directory.Exists(dllPath))
            {
                externalDll = Assembly.LoadFile(Path.Combine(dllPath, data.Source.FileName));
                try
                {
                    if (GetClassType(externalDll, data.FullName) == null)
                        return null;

                    object[] ctorArgs = initialState == AccessState.Default ? null : new object[] { initialState };
                    apb = (AccessPermissionBase)externalDll.CreateInstance(data.FullName, false, BindingFlags.CreateInstance, null, ctorArgs, null, null);

                }
                catch (TypeLoadException tle)
                {
                    Console.WriteLine(tle.Message);
                    return null;
                }
                catch (ArgumentNullException ane)
                {
                    Console.WriteLine(ane.Message);
                    return null;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    return null;
                }
            }
            return apb;
        }
    }
}